package com.xqkad.android.ui;

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class PullToRefreshLayout extends LinearLayout {
    /**
     * 回滚的时间
     */
    private static final int SCROLL_DURATION = 150;
    /**
     * 阻尼系数
     */
    private static final float OFFSET_RADIO = 2.5f;
    private float mLastMotionY = -1;
    private float mStartMotionY = 0;
    private int mTouchSlop;
    private SmoothScrollRunnable mSmoothScrollRunnable;
    private boolean mPullScrollEnabled = true;
    private View mHeader;
    private int mHeaderHeight = 0;

    public PullToRefreshLayout(Context context) {
        super(context);
    }

    public PullToRefreshLayout(Context context, AttributeSet attrs){
        super(context, attrs);
        init(context);
    }

    private void init(Context context){
        this.setOrientation(LinearLayout.VERTICAL);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        final TextView tv = new TextView(context);
        //tv.setTextColor();
        tv.setText("loading...");
        ViewGroup.MarginLayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        final int y = 30;
        lp.setMargins(230,y,0,y);
        tv.setLayoutParams(lp);
        tv.setTextSize(24);
        this.addView(tv,-1);
        tv.setVisibility(View.INVISIBLE);
        tv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

            @Override
            public void onGlobalLayout() {
                mHeader = tv;
                mHeaderHeight = y * 2 + tv.getMeasuredHeight();
                setPadding(0, -mHeaderHeight, 0, 0);
            }
        });
    }

    public interface OnRefresh{
        void onStartRefresh();
    }
    private OnRefresh onRefresh;
    public void setOnRefreshListener(OnRefresh listener){
        this.onRefresh = listener;
    }
    public void reset(){
        smoothScrollTo(0, SCROLL_DURATION, 0);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(!mPullScrollEnabled)
            return false;
        if(childCanDown())
            return false;

        boolean result = false;
        final int action = ev.getAction();
        //sc("int "+getScrollY(), 1);
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mLastMotionY = ev.getY();
                mStartMotionY = mLastMotionY;
                //MainActivity.sc("y ", t);
                break;

            case MotionEvent.ACTION_MOVE:
                final float deltaY = ev.getY() - mLastMotionY;
                final float absDiff = Math.abs(deltaY);
                if(absDiff > mTouchSlop && deltaY>0){
                    mLastMotionY = ev.getY();
                    mStartMotionY = mLastMotionY;
                    result = true;
                }
                break;

            case MotionEvent.ACTION_UP:

                break;

            default:
                break;
        }

        return result;
    }

    private boolean childCanDown(){
        for (int i = 1; i < getChildCount(); i++) {
            if(MyTools.canScrollDown(getChildAt(i)))
                return true;
        }
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if(!mPullScrollEnabled)
            return false;
        boolean result = false;
        final int action = ev.getAction();
        float y = ev.getY();
        //sc(y+" "+mStartMotionY, 2);

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //mLastMotionY = ev.getY();
                break;

            case MotionEvent.ACTION_MOVE:
                final float deltaY = y - mLastMotionY;
                mLastMotionY = y;
                if(y < mStartMotionY){
                    pullLayoutTo(0);
                    return true;
                }
                pullLayout(deltaY / OFFSET_RADIO);
                //pullLayout(deltaY);
                result = true;
                break;

            case MotionEvent.ACTION_UP:
                final int scrollY = getScrollY();
                int t = onPullDownFinish(scrollY);
                smoothScrollTo(t, SCROLL_DURATION, 0);
                break;

            default:
                break;
        }
        return result;
    }

    private int onPullDownFinish(int scrollY){
        if(-scrollY > mHeaderHeight){
            mPullScrollEnabled = false;
            onStartRefresh();
            return -mHeaderHeight;
        }else
            return 0;
    }
    private void onStartRefresh(){
        mHeader.setVisibility(View.VISIBLE);
        if(onRefresh != null)
            onRefresh.onStartRefresh();
    }

    private void pullLayout(float f){
        //v.offsetTopAndBottom((int) f);
        scrollBy(0, (int) -f);
    }
    private void pullLayoutTo(float f){
        scrollTo(0, (int) f);
    }
    private void smoothScrollTo(int value){
        smoothScrollTo(value, SCROLL_DURATION, 0);
    }
    private void smoothScrollTo(int newScrollValue, long duration, long delayMillis) {
        if (null != mSmoothScrollRunnable) {
            mSmoothScrollRunnable.stop();
        }

        int oldScrollValue = this.getScrollY();
        boolean post = (oldScrollValue != newScrollValue);
        if (post) {
            mSmoothScrollRunnable = new SmoothScrollRunnable(oldScrollValue, newScrollValue, duration);
        }

        if (post) {
            if (delayMillis > 0) {
                postDelayed(mSmoothScrollRunnable, delayMillis);
            } else {
                post(mSmoothScrollRunnable);
            }
        }
    }

    final class SmoothScrollRunnable implements Runnable{
        private final Interpolator mInterpolator;
        private final int mScrollToY;
        private final int mScrollFromY;
        private final long mDuration;
        private boolean mContinueRunning = true;
        private long mStartTime = -1;
        private int mCurrentY = -1;

        public SmoothScrollRunnable(int fromY, int toY, long duration) {
            mScrollFromY = fromY;
            mScrollToY = toY;
            mDuration = duration > 0 ? duration : 100;
            mInterpolator = new DecelerateInterpolator();
        }

        @Override
        public void run() {
            if(mStartTime == -1){
                mStartTime = System.currentTimeMillis();
            }else{
                final long oneSecond = 1000;    // SUPPRESS CHECKSTYLE
                long normalizedTime = (oneSecond * (System.currentTimeMillis() - mStartTime)) / mDuration;
                normalizedTime = Math.max(Math.min(normalizedTime, oneSecond), 0);

                final int deltaY = Math.round((mScrollFromY - mScrollToY)
                        * mInterpolator.getInterpolation(normalizedTime / (float) oneSecond));
                mCurrentY = mScrollFromY - deltaY;

                pullLayoutTo(mCurrentY);
            }

            if (mScrollToY != mCurrentY) {
                if(mContinueRunning)
                    PullToRefreshLayout.this.postDelayed(this, 16);// SUPPRESS CHECKSTYLE
            }else{
                onSmoothScrollFinish();
            }
        }

        /**
         * 停止滑动
         */
        public void stop() {
            mContinueRunning = false;
            removeCallbacks(this);
        }
    }

    private void onSmoothScrollFinish(){
        if(getScrollY() == 0){
            mPullScrollEnabled = true;
            mHeader.setVisibility(View.INVISIBLE);
        }
    }
}

class MyTools {

    public static boolean canScrollDown(View v) {
        if (android.os.Build.VERSION.SDK_INT < 14) {
            if (v instanceof AbsListView) {
                final AbsListView absListView = (AbsListView) v;
                return absListView.getChildCount() > 0
                        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
                        .getTop() < absListView.getPaddingTop());
            } else {
                return v.getScrollY() > 0;
            }
        } else {
            return ViewCompat.canScrollVertically(v, -1);
        }
    }

    public static boolean canScrollUp(View v){
        if (android.os.Build.VERSION.SDK_INT < 14){
            if(v instanceof AbsListView){
                final AbsListView absListView = (AbsListView) v;
                View lastChild = absListView.getChildAt(absListView.getChildCount() - 1);
                if (lastChild != null) {
                    return (absListView.getLastVisiblePosition() == (absListView.getCount() - 1))
                            && lastChild.getBottom() > absListView.getPaddingBottom();
                } else {
                    return false;
                }
            }else{
                return v.getHeight() - v.getScrollY() > 0;
            }
        }else{
            return ViewCompat.canScrollVertically(v, 1);
        }
    }
}
